## 来自多分类的混淆矩阵实现
def calculate_recall_precision(label, score):
    instance_num, class_num = score.shape
    rank = score.argsort()
    confusion_matrix = np.zeros([class_num, class_num])

    for i in range(instance_num):
        true_l = label[i]
        pred_l = rank[i, -1]
        confusion_matrix[true_l][pred_l] += 1

    precision = []
    recall = []

    for i in range(class_num):
        true_p = confusion_matrix[i][i]
        false_n = sum(confusion_matrix[i, :]) - true_p
        false_p = sum(confusion_matrix[:, i]) - true_p
        precision.append(true_p * 1.0 / (true_p + false_p))
        recall.append(true_p * 1.0 / (true_p + false_n))

    return precision, recall

## 来自语义分割的 混淆矩阵的实现
class Metrics:
    def __init__(self, numclass=12):
        self.numclass = numclass
        self.confusionMatrix = np.zeros((self.numclass, self.numclass))

    def pixelAccuracy(self):
        # acc = (TP + TN) / (TP + TN + FP + TN)
        molecule = np.diag(self.confusionMatrix) #提取对角线 TP
        molecule = np.sum(molecule)
        denominator = np.sum(self.confusionMatrix)
        return molecule / (denominator+1e-6)

    def classPixelAccuracy(self):
        # pi = TP / TP + FP
        PIs = np.sum(self.confusionMatrix,axis=1)
        molecule = np.diag(self.confusionMatrix)
        return molecule / PIs

    def meanPixelAccuracy(self):
        classpixelacc = self.classPixelAccuracy()
        meanacc = np.nanmean(classpixelacc)
        return meanacc

    def meanIntersectionOverUnion(self):
        intersection = np.diag(self.confusionMatrix)
        FP = np.sum(self.confusionMatrix,axis=1)
        FN = np.sum(self.confusionMatrix,axis=0)
        union = FP + FN - intersection
        oiou = intersection / union
        meaniou = np.nanmean(oiou)
        return meaniou

    def genConfusionMatrix(self, pred, label):
        # 背景也算上
        mask = 0 <= label < self.numclass
        # REW: 计算所有类的混淆矩阵
        board = self.numclass*label[mask]+pred[mask]
        board = np.bincount(board,minlength=self.numclass**2)
        confusionMatrix = board.reshape((self.numclass,self.numclass))
        return confusionMatrix

    def addBatch(self,imgpred,imglabel):
        assert imgpred.shape == imglabel.shape
        self.confusionMatrix += self.genConfusionMatrix(imgpred,imglabel)

    def reset(self):
        self.confusionMatrix = np.zeros((self.numclass, self.numclass))


def top_k_by_category(label, score, top_k):
    instance_num, class_num = score.shape
    rank = score.argsort()
    # REW:按类别来统计准确率
    hit_top_k = [[] for i in range(class_num)]
    for i in range(instance_num):
        l = label[i] # 选择第i个实例，标签为l
        # 然后标签l在topK命中的情况
        hit_top_k[l].append(l in rank[i, -top_k:])

    accuracy_list = []
    # 对于每一个标签命中的情况
    for hit_per_category in hit_top_k:
        if hit_per_category:
            accuracy_list.append(sum(hit_per_category) * 1.0 / len(hit_per_category))
        else:
            accuracy_list.append(0.0)
    return accuracy_list